home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-08 | 39.4 KB | 1,352 lines | [TEXT/KAHL] |
- //----------------------- © 1992-1995 by James G. Stout ----------------------------
- // File : cdefDtc.c
- // Date : 20 June 1992
- // Author : Jim Stout
- // :
- // Purpose : a "Date Time Control" CDEF that allows adjustment of date
- // : and time as in the General Control Panel. Clicking on the
- // : date or time will show a 'small arrow' type control for
- // : date or time adjustment.
- // :
- // : see cdefDtc.h for more detail and variation codes
- // :
- // : If you find a use for this, I'd love to know about it. Bug reports
- // : are always interesting.
- // :
- // : Internet : JimS@WRQ.COM(work hours, PST)
- // : AppleLink : WRQ (daily)
- // : CompuServe : 73240,2052 (weekly or so)
- // : AOL : JasG (weekly or so)
- // : eWorld : Jim Stout (weekly or so)
- //----------------------------------------------------------------------------------
- //#define _DEBUGCDEF 1
-
-
- #include "fatCDEF.h"
-
- #include <Controls.h>
- #include <GestaltEqu.h>
- #include <LowMem.h>
- #include <Memory.h>
- #include <Packages.h>
- #include <QDOffscreen.h>
- #include <ToolUtils.h>
- #include <Types.h>
-
- #include "colorCDEF.h"
- #include "grayCDEF.h"
- #include "miscCDEF.h"
- #include "qdCDEF.h"
-
- #include "cdefDtc.h"
-
- #ifdef _DEBUGCDEF
- pascal long CDmain (short, ControlHandle, short, long);
-
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
- #else
-
- //==================================================================================
- // CDEF entry point
- //==================================================================================
- pascal long main (short varCode, ControlHandle theCtl, short message, long param)
- #endif
- {
- long ret = 0L;
- short txF, txS, partCode,myVarCode=0;
- GrafPtr thisPort;
- SignedByte cState, dState;
-
- #include "fatEntry.c"
-
- cState = HGetState((Handle)theCtl);
- HLock((Handle)theCtl);
-
- //----------------------------------------------------------------------------------
- // make sure we've got the correct font…
- //----------------------------------------------------------------------------------
-
- if(!(varCode & useWindFont)) { // don't use the window font
- GetPort(&thisPort);
- txF = thisPort->txFont;
- txS = thisPort->txSize;
- TextFont(LMGetSysFontFam()); // set system as current
- TextSize(LMGetSysFontSize());
- }
-
- //----------------------------------------------------------------------------------
- // lock down the cdef data and get our 'custom' variation code
- //----------------------------------------------------------------------------------
-
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- myVarCode = (**(dtcHandle)(**theCtl).contrlData).varCode;
- }
-
- partCode = LoWord(param);
-
- //----------------------------------------------------------------------------------
- // handle the standard control messages
- //----------------------------------------------------------------------------------
-
- switch(message) {
- case initCntl:
- doInit(theCtl, varCode);
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
- break;
- case dispCntl:
- doDisp(theCtl);
- break;
- case testCntl:
- ret = doTest (theCtl, myVarCode, param);
- break;
- case drawCntl:
- if((**theCtl).contrlVis != 0 &&
- ((WindowPeek)(**theCtl).contrlOwner)->visible) {
- doDraw(theCtl, myVarCode, partCode);
- }
- break;
- case calcCRgns:
- RectRgn((RgnHandle)(param & 0x7fffffffL), &(**theCtl).contrlRect);
- break;
- case calcCntlRgn:
- case calcThumbRgn:
- RectRgn((RgnHandle)(param), &(**theCtl).contrlRect);
- break;
- }
-
- //----------------------------------------------------------------------------------
- // restore window font & size info
- //----------------------------------------------------------------------------------
-
- if(!(varCode & useWindFont)) {
- TextFont(txF);
- TextSize(txS);
- }
-
- if((**theCtl).contrlData)
- HSetState((**theCtl).contrlData, dState);
- HSetState((Handle)theCtl, cState);
-
- #include "fatExit.c"
-
- return (ret);
- }
-
- //==================================================================================
- // initialize our data
- //==================================================================================
-
- static void doInit (ControlHandle theCtl, short varCode)
- {
- dtcHandle hCDEF;
- Intl0Hndl hInt;
- short inx;
-
- hCDEF = (dtcHandle) NewHandle(sizeof(dtcData));
- if(hCDEF) {
- for(inx=0;inx<6;inx++)
- (**hCDEF).poly[inx] = 0;
- (**hCDEF).arrowHilite = 0;
- (**hCDEF).varCode = varCode; // save original varCode
- (**hCDEF).qdVers = getQDVers(); // QuickDraw version
- (**hCDEF).offPort = 0; // gets created in doDraw
- (**hCDEF).pDepth = 1;
- (**hCDEF).currSel = 0;
-
- hInt = (Intl0Hndl)IUGetIntl(0);
-
- (**hCDEF).dateSep = (**hInt).dateSep;
- (**hCDEF).dateOrder = (**hInt).dateOrder;
- (**hCDEF).timeSep = (**hInt).timeSep;
- (**hCDEF).timeCycle = (**hInt).timeCycle;
-
- //----------------------------------------------------------------------------------
- // contrlMax & controlMin are used as "extended" variation codes
- //----------------------------------------------------------------------------------
-
- if(!(**theCtl).contrlMax) { // use ControlPanel 12/24 setting
- if((**hInt).timeCycle != 0) // set for AM/PM
- (**hCDEF).varCode ^= showAMPM; // so, set our varCode
- }
- (**theCtl).contrlMax = 9;
-
- if((**theCtl).contrlMin) { // if non-zero, wants 3D arrows
- (**hCDEF).varCode ^= ctl3D; // so, set our varCode
- (**theCtl).contrlMin = 0;
- }
- (**theCtl).contrlData = (Handle)hCDEF;
- }
- else
- (**theCtl).contrlData = 0;
- }
-
- //==================================================================================
- // dispose of our data
- //==================================================================================
-
- static void doDisp (ControlHandle theCtl)
- {
- dtcHandle hCDEF;
- short inx;
- BitMap *theBits;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(hCDEF) {
- if((**hCDEF).offPort) {
- if(((**hCDEF).offPort->portVersion & 0x8000) != 0) { // offPort is GWorld
- DisposeGWorld((**hCDEF).offPort);
- }
- else { // offport is bitmap
- theBits = &((GrafPtr)(**hCDEF).offPort)->portBits;
- DisposePtr((*theBits).baseAddr);
- ClosePort((GrafPtr)(**hCDEF).offPort);
- DisposePtr((Ptr)(**hCDEF).offPort);
- }
- }
-
- for(inx=0;inx<6;inx++) {
- if((**hCDEF).poly[inx])
- KillPoly((**hCDEF).poly[inx]);
- }
- HUnlock((Handle)hCDEF);
- DisposeHandle((Handle)hCDEF);
- (**theCtl).contrlData = 0;
- }
- }
-
- //==================================================================================
- // check for a mouseDown in our control
- //==================================================================================
-
- static long doTest (ControlHandle theCtl, short varCode, long param)
- {
- Point p;
- short inx,start, end;
- long ret=0L;
- Rect parts[NUMPARTS];
- Boolean hit;
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return(ret);
-
- p.h = LoWord(param); // get the mouse hit point
- p.v = HiWord(param);
-
- start = HOURS; // set loop variables
- end = DOWNDATE;
-
- if(varCode & timeOnly)
- end = DOWNTIME;
- else
- if(varCode & dateOnly)
- start = DT1;
-
- if(PtInRect(p,&(**theCtl).contrlRect)) { // click in control
- getRects(theCtl, varCode, parts);
- (**hCDEF).arrowHilite = 0; // arrow not hilited
-
- //----------------------------------------------------------------------------------
- // first, test for a simple click in one of the digit fields
- //----------------------------------------------------------------------------------
-
- for(inx = start;inx <= end;inx++) { // loop through all parts
- if(PtInRect(p,&parts[inx])) { // and check for a mouse down
- if(!arrowPart(inx)) { // click in a digit, not in
- while(StillDown()) { // an arrow.
- }
- GetMouse(&p);
- if(PtInRect(p,&parts[inx])) {
- (**theCtl).contrlValue = inx;
- return((long)inx); // all done
- }
- else
- return (0L);
- }
- }
- }
-
- //----------------------------------------------------------------------------------
- // second, check for a click in an arrow
- //----------------------------------------------------------------------------------
-
- if((**theCtl).contrlValue) { // an arrow is visible
- if((**theCtl).contrlValue <= AMPM) { // time arrow
- start = UPTIME;
- end = DOWNTIME;
- }
- else { // date arrow
- start = UPDATE;
- end = DOWNDATE;
- }
- for (inx=start;inx<=end;inx++) { // check for press in arrow
- if(PtInRect(p,&parts[inx])) {
- while (StillDown()) { // and track it…
- if(PtInRect(p,&parts[inx])) { // mouse hasn't moved… so
- (**hCDEF).arrowHilite = inx; // hilite & update value…
- updateValue (theCtl, varCode, inx);
- hit = true;
- ret = (long)inx;
- }
- else
- if(hit) { // mouse moved outside arrow
- (**hCDEF).arrowHilite = 0; // so un-hilite arrow…
- doDraw(theCtl, varCode, ALL);
- hit = false;
- ret = 0L;
- }
- GetMouse(&p); // get new mouse location
- }
- }
- }
- if(hit) { // un-hilite arrow, mouse
- (**hCDEF).arrowHilite = 0; // came up...
- doDraw(theCtl, varCode, ALL);
- ret = 0;
- }
- }
- }
- return(ret);
- }
-
- //==================================================================================
- // update the control value
- //==================================================================================
-
- static void updateValue (ControlHandle theCtl, short varCode, short partCode)
- {
- short selected,m,d,y,dateTbl[3];
- unsigned long secs;
- DateTimeRec dtr;
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return;
-
- if(!arrowPart(partCode)) // only track the up/down arrows
- return;
-
- selected = (**theCtl).contrlValue; // the item to adjust
- secs = GetCRefCon(theCtl); // get current date/time setting
- Secs2Date(secs,&dtr); // convert to a DateTimeRecord
-
- getDateFmt(theCtl, &m, &d, &y);
- dateTbl[d] = dtr.day;
- dateTbl[m] = dtr.month;
- dateTbl[y] = dtr.year;
-
- switch(selected) { // now, bump the selected item up or down
- case MINUTES:
- if(partCode == UPTIME)
- secs += 60;
- else
- secs -= 60;
- break;
- case HOURS:
- if(partCode == UPTIME)
- secs += 3600;
- else
- secs -= 3600;
- break;
- case AMPM:
- if(dtr.hour < 12)
- dtr.hour+=12;
- else
- dtr.hour-=12;
- break;
- case DT1:
- if(partCode == UPDATE)
- dateTbl[m]++;
- else
- dateTbl[m]--;
- if(dateTbl[m] > 12) {
- dateTbl[y]++;
- dateTbl[m] = 1;
- }
- else
- if(dateTbl[m] < 1) {
- dateTbl[y]--;
- dateTbl[m] = 12;
- }
- break;
- case DT2:
- if(partCode == UPDATE)
- dateTbl[d]++;
- else
- dateTbl[d]--;
- break;
- case DT3:
- if(partCode == UPDATE)
- dateTbl[y]++;
- else
- if(dateTbl[y] > 1904) // ROM routine only good since 1904,
- dateTbl[y]--; // the year the Mac was invented !
- break;
- }
- dtr.day = dateTbl[d];
- dtr.month = dateTbl[m];
- dtr.year = dateTbl[y];
-
- if(selected != HOURS && selected != MINUTES)
- Date2Secs(&dtr, &secs); // convert date rec back to seconds
-
- SetCRefCon(theCtl,secs); // save the new date & time
- doDraw(theCtl, varCode, ALL); // draw the new date & time
- Delay(10L, (long *)&secs); // pause a bit
- }
-
- //==================================================================================
- // process the drawCntl message
- //==================================================================================
-
- void doDraw(ControlHandle theCtl, short varCode, short partCode)
- {
- WindowPeek w;
- RgnHandle saveClip, newClip;
- Boolean inactive=false,inColor=false,bgInColor=false;
- Boolean haveGW=false,haveGray=false, backPat=false;
- PenState penSt;
- unsigned long secs;
- short h,v,oldVal,toDraw;
- Str31 s1;
- Rect r;
- BitMap *offBits;
- Rect parts[NUMPARTS];
- CGrafPtr savePort;
- GDHandle saveGDev;
- PixMapHandle pmHdl;
- RGBColor saveFore,saveBack;
- RGBColor rgbBlack = {0,0,0};
- RGBColor rgbWhite = {-1,-1,-1};
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return;
-
- w = (WindowPeek)(**theCtl).contrlOwner; // don't draw if window is
- if(!w->visible || arrowPart(partCode)) { // invisible or if partCode
- return; // is an up/down arrow
- }
- if((**theCtl).contrlHilite == 0xFF) {
- inactive = true;
- }
- else
- if((**theCtl).contrlHilite > 0 && // we hilite differently
- !arrowPart((short)(**theCtl).contrlHilite)) { // from normal controls
- return;
- }
-
- if(partCode == 129)
- partCode = (**theCtl).contrlValue;
-
- getRects(theCtl, varCode, parts); // rects for control parts
-
- //----------------------------------------------------------------------------------
- // now, update our GWorld if required, and set it as our drawing port
- //----------------------------------------------------------------------------------
-
- (**hCDEF).pDepth = getOff(&(**hCDEF).offPort, &parts[ALL]);
-
- if((**hCDEF).pDepth == 0) { // oh… oh…
- return;
- }
-
- if(((**hCDEF).offPort->portVersion & 0x8000) != 0) { // have a GWorld
- haveGW = true;
- pmHdl = getLockedPixels(&(**hCDEF).offPort, (**hCDEF).qdVers);
- if(!pmHdl)
- return; // nuts…
- }
-
- //----------------------------------------------------------------------------------
- // Do the clip region properly. Thanks Ari!
- //----------------------------------------------------------------------------------
-
- r = (**theCtl).contrlRect; // the rect we draw in
- saveClip = NewRgn();
- GetClip(saveClip);
-
- newClip = NewRgn();
- RectRgn(newClip, &r);
- SectRgn(saveClip, newClip, newClip);
-
- if(EmptyRgn(newClip)) { // if empty, don't waste
- DisposeRgn(saveClip); // time drawing...
- DisposeRgn(newClip);
- return;
- }
-
- SetClip(newClip);
-
- //----------------------------------------------------------------------------------
- // initialize our drawing stuff
- //----------------------------------------------------------------------------------
-
- if((**hCDEF).pDepth > 2) { // save current port
- inColor = true; // colors
- saveColors(&saveFore, &saveBack);
- bgInColor = true;
- if(saveBack.red == 65535 && // is bg white?
- saveBack.green == 65535 &&
- saveBack.blue == 65535)
- bgInColor = false;
- }
- #ifdef NOEMBOSS
- bgInColor = false;
- #endif
-
- //----------------------------------------------------------------------------------
- // Set for drawing in offscreen port
- //----------------------------------------------------------------------------------
- if(haveGW) { // set offscreen for drawing
- GetGWorld(&savePort, &saveGDev);
- SetGWorld((**hCDEF).offPort, nil);
- } else {
- GetPort((GrafPtr*)&savePort);
- SetPort((GrafPtr)(**hCDEF).offPort);
- }
- if(inColor) { // set colors in offPort
- RGBForeColor(&saveFore);
- RGBBackColor(&saveBack);
- setPartColor(theCtl, cTextColor, true);
- }
- else {
- ForeColor(blackColor);
- BackColor(whiteColor);
- }
- if(varCode & useWindFont) { // set font in offPort
- (**hCDEF).offPort->txFont = savePort->txFont;
- (**hCDEF).offPort->txSize = savePort->txSize;
- }
-
- if(haveGW) { // we have a pixMap
- offBits = (BitMap *)*pmHdl;
- if((**(*savePort).bkPixPat).patType != 0 &&
- (savePort->portVersion & 0x8000) != 0) {
- backPat = true;
- BackPixPat((*savePort).bkPixPat);
- }
- }
- else { // we have a bitMap
- offBits = (BitMap *)&((GrafPtr)(**hCDEF).offPort)->portBits;
- }
-
- //----------------------------------------------------------------------------------
- // Erase background of offscreen port - pay attention to origin so patterned
- // backgrounds are aligned
- //----------------------------------------------------------------------------------
-
- SetOrigin((**theCtl).contrlRect.left, (**theCtl).contrlRect.top);
- EraseRect(&(**theCtl).contrlRect);
- SetOrigin(0,0);
-
- //----------------------------------------------------------------------------------
- // Draw the control title
- //----------------------------------------------------------------------------------
-
- OffsetRect(&parts[TITLE], -parts[ALL].left, -parts[ALL].top);
- h = parts[TITLE].left + 1;
- v = parts[TITLE].bottom-parts[FONTINFO].bottom;
- if(bgInColor && varCode & ctl3D) {
- RGBForeColor(&rgbWhite);
- MoveTo(h+1,v+1);
- DrawString((**theCtl).contrlTitle);
- setPartColor(theCtl, cTextColor, true);
- }
- if(inactive && inColor) { // control is inactive
- if(haveGrayText()) { // draw in gray
- TextMode(grayishTextOr);
- haveGray = true;
- }
- }
- MoveTo(h,v);
- DrawString((**theCtl).contrlTitle); // draw the title
- TextMode(srcOr);
-
- //----------------------------------------------------------------------------------
- // Get the refCon - our control 'value' or initialize if needed
- //----------------------------------------------------------------------------------
-
- secs = GetCRefCon(theCtl); // control 'value' in refCon
- if(secs == 0) { // nothing there
- GetDateTime(&secs);
- SetCRefCon(theCtl, secs); // plug in current time
- }
-
- //----------------------------------------------------------------------------------
- // Convert to a date string and draw date
- //----------------------------------------------------------------------------------
-
- if(!(varCode & timeOnly)) {
- getDateStr(theCtl, secs, s1);
- OffsetRect(&parts[DATE], -parts[ALL].left, -parts[ALL].top);
- h = parts[DATE].left + 1;
- v = parts[DATE].bottom-parts[FONTINFO].bottom;
- if(bgInColor && varCode & ctl3D) { // embossed 3D effect
- RGBForeColor(&rgbWhite);
- MoveTo(h+1,v+1);
- DrawString(s1);
- setPartColor(theCtl, cTextColor, true);
- }
- if(haveGray) // means inactive
- TextMode(grayishTextOr);
- MoveTo(h,v);
- DrawString(s1);
- TextMode(srcOr);
- }
-
- //----------------------------------------------------------------------------------
- // Convert to a time string and draw time
- //----------------------------------------------------------------------------------
-
- if(!(varCode & dateOnly)) {
- getTimeStr(theCtl, varCode, secs, s1);
- OffsetRect(&parts[HOURS], -parts[ALL].left, -parts[ALL].top);
- h = parts[HOURS].left + 1;
- v = parts[HOURS].bottom-parts[FONTINFO].bottom;
- if(bgInColor && varCode & ctl3D) { // embossed 3D effect
- RGBForeColor(&rgbWhite);
- MoveTo(h+1,v+1);
- DrawString(s1);
- setPartColor(theCtl, cTextColor, true);
- }
- if(haveGray) // means inactive
- TextMode(grayishTextOr);
- MoveTo(h,v);
- DrawString(s1);
- TextMode(srcOr);
- }
- TextMode(srcOr);
-
- if(partCode == ALL)
- oldVal = (**theCtl).contrlValue;
- else
-
- //----------------------------------------------------------------------------------
- // set new value for control - actually, this indicates the hilited digits,
- // the actual dateTime value is stored in the control refcon!
- //----------------------------------------------------------------------------------
-
- if(!arrowPart(partCode)) {
-
- //----------------------------------------------------------------------------------
- // if inactive control, reset control value to deselect digits
- //----------------------------------------------------------------------------------
-
- if((**theCtl).contrlHilite == 0xFF) {
- (**hCDEF).currSel = (**theCtl).contrlValue = 0;
- }
- else {
-
- //----------------------------------------------------------------------------------
- // if click on currently selected digits, deselect & remove hiliting
- // by setting value to 0
- //----------------------------------------------------------------------------------
-
- if((**theCtl).contrlValue == partCode) {
- if((**hCDEF).currSel == (**theCtl).contrlValue) {
- (**hCDEF).currSel = (**theCtl).contrlValue = 0;
- }
- else
- (**hCDEF).currSel = (**theCtl).contrlValue;
- }
-
- //----------------------------------------------------------------------------------
- // click on new digits, select by setting value to hilite
- //----------------------------------------------------------------------------------
-
- else {
- if(partCode < 0xFF) {
- if(partCode < 10)
- (**theCtl).contrlValue = partCode;
- (**hCDEF).currSel = 0;
- }
- }
- }
- }
-
- //----------------------------------------------------------------------------------
- // Draw the arrows into the offscreen port if needed
- //----------------------------------------------------------------------------------
- if((**theCtl).contrlValue && !inactive) { // only if selected & active
-
- if(!(**hCDEF).poly[0]) // create polygons for
- makePolys(theCtl, varCode); // arrows
-
- if((**hCDEF).arrowHilite) // arrow to draw hilited
- toDraw = (**hCDEF).arrowHilite;
- else
- if(partCode > 0 && partCode < 10)
- toDraw = partCode; // arrow not hilited
- else
- toDraw = (**theCtl).contrlValue; // arrow not hilited
-
- drawArrows(theCtl, varCode, toDraw, inColor);
- }
-
- //----------------------------------------------------------------------------------
- // use CopyBits to draw the control onscreen
- //----------------------------------------------------------------------------------
-
- if(haveGW) { // back to onscreen port
- SetGWorld(savePort, saveGDev);
- } else {
- SetPort((GrafPtr)savePort);
- }
- if(inColor) {
- RGBForeColor(&rgbBlack);
- RGBBackColor(&rgbWhite);
- }
- CopyBits(offBits, // from bitmap
- &((GrafPtr)savePort)->portBits, // to onscreen port
- &(**hCDEF).offPort->portRect, // from rect
- &parts[ALL], // to rect
- srcCopy, nil);
-
- if(haveGW) {
- unlockPixels(pmHdl, (**hCDEF).qdVers);
- DisposeGWorld((**hCDEF).offPort);
- (**hCDEF).offPort = 0;
- }
- if(inColor) {
- restoreColors(&saveFore, &saveBack);
- }
-
- //----------------------------------------------------------------------------------
- // hilite the selected digits - contrlValue is currently selected field
- //----------------------------------------------------------------------------------
-
- if(partCode == ALL) { // entire control redrawn
- if(oldVal)
- doHilite(theCtl, varCode, oldVal, backPat);
- }
- else {
- doHilite(theCtl, varCode, // hilite part clicked on
- (**theCtl).contrlValue, backPat);
- }
-
- //----------------------------------------------------------------------------------
- // if inactive & no GrayishTextOr, gray out the control the old way
- //----------------------------------------------------------------------------------
-
- if(inactive && !haveGray) {
- GetPenState(&penSt);
- PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55");
- PenMode(patBic);
- PaintRect(&r);
- SetPenState(&penSt);
- }
-
- SetClip(saveClip);
- DisposeRgn(saveClip);
- DisposeRgn(newClip);
- }
-
- //----------------------------------------------------------------------------------
- // Hilite the digit parts of the control
- //----------------------------------------------------------------------------------
-
- static void doHilite(ControlHandle theCtl, short varCode, short partCode,
- Boolean backPat)
- {
- Rect parts[NUMPARTS];
- dtcHandle hCDEF;
- unsigned char hiliteMode;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return;
-
- if ((partCode >= HOURS && partCode <= AMPM) ||
- (partCode >= DT1 && partCode <= DT3)) {
-
- getRects(theCtl, varCode, parts);
-
- if(backPat)
- FrameRect(&parts[partCode]);
- else {
- hiliteMode = LMGetHiliteMode();
- LMSetHiliteMode(pHiliteBit);
- InvertRect(&parts[partCode]);
- LMSetHiliteMode(hiliteMode);
- ValidRect(&parts[partCode]);
- }
- }
- }
- //==================================================================================
- // Draw the actual arrow control image.
- //
- //==================================================================================
-
- static void drawArrows(ControlHandle theCtl, short varCode, short toDraw,
- Boolean inColor)
- {
- short inx,base;
- Rect arrowRect,parts[NUMPARTS];
- RGBColor rgbBlack = {0,0,0};
- RGBColor rgbWhite = {-1,-1,-1};
- RGBColor rgbA = {0xAAAA, 0xAAAA, 0xAAAA};
- RGBColor grayColor;
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
-
- getRects(theCtl, varCode, parts); // rects for control parts
-
- if(toDraw < DT1)
- base = 0;
- else
- base = 1;
-
- //----------------------------------------------------------------------------------
- // Frame the arrow box then fill & shadow if 3D
- //----------------------------------------------------------------------------------
-
- if((**hCDEF).poly[base*3]) {
- ForeColor(whiteColor);
- PaintPoly((**hCDEF).poly[base*3]);
- ForeColor(blackColor);
- if(inColor) {
- setPartColor(theCtl, cFrameColor, true);
- }
- FramePoly((**hCDEF).poly[base*3]);
-
- //----------------------------------------------------------------------------------
- // draw shadow if 3D arrow
- //----------------------------------------------------------------------------------
-
- if(inColor && varCode & ctl3D) {
- if(toDraw < DT1) {
- arrowRect = parts[FRAMET];
- OffsetRect(&arrowRect, -parts[ALL].left, -parts[ALL].top);
- }
- else {
- arrowRect = parts[FRAMED];
- OffsetRect(&arrowRect, -parts[ALL].left, -parts[ALL].top);
- }
- RGBForeColor(&rgbA);
-
- MoveTo(arrowRect.left+1, arrowRect.bottom-1);
- LineTo(arrowRect.left-1, arrowRect.bottom-3);
- LineTo(arrowRect.left-1, arrowRect.top+3);
- Move(0,-1);
- LineTo(arrowRect.left+2, arrowRect.top-1);
- LineTo(arrowRect.right-4, arrowRect.top-1);
-
- ForeColor(whiteColor);
- Move(1,0);
- LineTo(arrowRect.right, arrowRect.top+2);
- LineTo(arrowRect.right, arrowRect.bottom-3);
- LineTo(arrowRect.right-3, arrowRect.bottom);
- LineTo(arrowRect.left+2, arrowRect.bottom);
-
- setPartColor(theCtl, cFrameColor, true);
- }
- }
-
- //----------------------------------------------------------------------------------
- // The small, non-3D arrows are hilited by filling the top/bottom half
- // of the frame with the bgColor. Then we fill/paint the arrow poly in white.
- //----------------------------------------------------------------------------------
-
- if(!(varCode & ctl3D) || !inColor) {
- if((**hCDEF).arrowHilite) {
- arrowRect = parts[toDraw];
- OffsetRect(&arrowRect, -parts[ALL].left, -parts[ALL].top);
- if(toDraw == UPDATE || toDraw == UPTIME)
- MoveTo(arrowRect.left+1, arrowRect.top+1);
- else
- MoveTo(arrowRect.left+1,arrowRect.top-1);
- for(inx=0;inx<8;inx++) {
- Line(8,0);
- Move(-8,1);
- }
- }
- }
- //----------------------------------------------------------------------------------
- // draw both the top & bottom arrows (poly[1] & poly[2])
- //----------------------------------------------------------------------------------
-
- for(inx=1;inx<3;inx++) {
- if((**hCDEF).poly[base*3+inx]) { // Need the poly!
- //----------------------------------------------------------------------------------
- // First check to see if we are drawing a hilited arrow
- //----------------------------------------------------------------------------------
- if(toDraw-4 == inx ||
- toDraw-9 == inx) { // arrow is hilited
- if(inColor) {
- if(varCode & ctl3D)
- RGBForeColor(&rgbBlack); // in black for 3D arrows
- else
- RGBForeColor(&rgbWhite); // in white for non-3D
- }
- else // b&w hilited arrow
- ForeColor(whiteColor); // must draw white
- PaintPoly((**hCDEF).poly[base*3+inx]); // draw the arrow
- }
- //----------------------------------------------------------------------------------
- // Nope, it is not hilited
- //----------------------------------------------------------------------------------
- else // make it look like a
- if(varCode & ctl3D) { // scroll bar arrow
- if(inColor) { // with lighter center
- setPartColor(theCtl, cTingeLight, true);
- GetForeColor(&grayColor);
- grayColor.red -= 13107;
- grayColor.green -= 13107;
- grayColor.blue -= 13107;
- RGBForeColor(&grayColor);
- PaintPoly((**hCDEF).poly[base*3+inx]);
- setPartColor(theCtl, cTingeDark, true);
- }
- else // in 3D, but in b&w
- PaintPoly((**hCDEF).poly[base*3+inx]); // so arrow is solid fgColor
- }
- else // not 3D, so arrow
- PaintPoly((**hCDEF).poly[base*3+inx]); // is solid fgColor
-
- FramePoly((**hCDEF).poly[base*3+inx]); // frame the arrow
- }
-
- if(inColor) // set fg for next arrow
- setPartColor(theCtl, cFrameColor, true);
- else
- ForeColor(blackColor);
- }
- }
-
- //==================================================================================
- // Get the rectangles for each part of the control. These are used for
- // detecting mouse actions and hiliting the date & time digits.
- //==================================================================================
- static void getRects (ControlHandle theCtl, short varCode, Rect parts[])
- {
- short ht,wid,tWid,offset,inx,m,d,y;
- Rect base,work,up,down,mR,dR,yR;
- FontInfo f;
- char sStr[9];
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return;
-
- sStr[0] = 8; // sample "88/88/88"
- sStr[3] = sStr[6] = (**hCDEF).dateSep;
- sStr[1] = sStr[2] = sStr[4] = sStr[5] = sStr[7] = sStr[8] = '8';
-
- getDateFmt(theCtl, &m, &d, &y);
- GetFontInfo(&f);
- ht = f.ascent + f.descent+f.leading;
- if(f.leading == 0)
- ht++;
-
- base = (**theCtl).contrlRect; // the entire control
- parts[ALL] = base;
- tWid = StringWidth((**theCtl).contrlTitle);
- if(tWid)
- tWid+=5;
- base.left+=tWid;
- parts[FONTINFO] = base;
- parts[FONTINFO].bottom = ht - f.ascent; // baseline for DrawStr
-
- //----------------------------------------------------------------------------------
- // part rectangles for Date portion of control; left justified
- //----------------------------------------------------------------------------------
-
- base.top = base.bottom - ARROWHT; // resize to arrow height
- up = work = base; // the up arrow rect
- up.left += StringWidth((StringPtr)sStr) + 6; // shift arrow to right
- up.right = up.left + ARROWID; // resize arrow width
- parts[FRAMED] = down = up; // up & down are full rects
- up.bottom = up.top + (up.bottom - up.top)/2; // split them in half
-
- parts[UPDATE] = up; // up rect is top half
- down.top = up.bottom+1;
- parts[DOWNDATE] = down; // down rect is bottom half
-
- wid = StringWidth("\p88")+2; // digit rect for 2 numbers
- work.right = work.left + wid;
- offset = (ARROWHT - ht)/2; // center digits in rect
- work.bottom -= offset;
- work.top = (work.bottom-ht)/2 * 2;
-
- parts[TITLE] = work;
- parts[TITLE].left = parts[ALL].left;
- tWid = StringWidth((**theCtl).contrlTitle);
- if(tWid)
- tWid+=5;
- parts[TITLE].right = parts[TITLE].left+tWid;
-
- parts[DT1] = parts[DATE] = work; // the first digits rect
- offset = CharWidth((**hCDEF).dateSep)-2; // a bit of fudge here
- OffsetRect(&work, wid+offset,0); // offset the other rects
- parts[DT2] = work;
- OffsetRect(&work, wid+offset,0);
- parts[DT3] = work;
-
- //----------------------------------------------------------------------------------
- // part rectangles for Time portion of control; right justified
- //----------------------------------------------------------------------------------
-
- sStr[0] = 8; // sample "88:88 AM"
- sStr[3] = (**hCDEF).timeSep;
- sStr[1] = sStr[2] = sStr[4] = sStr[5] = '8';
- sStr[6] = ' ';
- sStr[7] = 'A';
- sStr[8] = 'M';
-
- //----------------------------------------------------------------------------------
- // build rects for up and down portion of arrow, right justified in cntrolRect
- //----------------------------------------------------------------------------------
-
- up = base; // base rect
- OffsetRect(&up,-1,0);
- work = up;
- up.left = up.right - ARROWID; // shift arrow to right
- parts[FRAMET] = down = up; // up & down are full rects
- up.bottom = up.top + (up.bottom - up.top)/2; // split them in half
-
- parts[UPTIME] = up; // up rect is top half
- down.top = up.bottom+1;
- parts[DOWNTIME] = down; // down rect is bottom half
-
- //----------------------------------------------------------------------------------
- // build rects for digit portion of time string
- //----------------------------------------------------------------------------------
-
- offset = (ARROWHT - ht)/2; // center digits in rect
- work.bottom -= offset;
- work.top = (work.bottom-ht)/2 * 2;
- if(varCode & showAMPM) // set timeRect.left
- work.left = up.left - (StringWidth((StringPtr)sStr) + 6);
- else {
- sStr[0] = 5;
- work.left = up.left - (StringWidth((StringPtr)sStr) + 6);
- }
- work.right = work.left+wid; // enough room for 2 digits
-
- parts[HOURS] = work; // hours digit rect
-
- offset = CharWidth((**hCDEF).timeSep)-2; // a little fudge…
- OffsetRect(&work,wid+offset,0);
- parts[MINUTES] = work; // minutes digit rect
-
- if(varCode & showAMPM) { // set up AM/PM rect
- offset = CharWidth(' ')-2; // a little fudge…
- OffsetRect(&work,wid+offset,0);
- wid = StringWidth("\pPM");
- work.right = work.left+wid+2;
- }
- else
- SetRect(&work,0,0,0,0); // no AM/PM, so no rect
-
- parts[AMPM] = work;
-
-
- //----------------------------------------------------------------------------------
- // shift rects around to match date format
- //----------------------------------------------------------------------------------
-
- mR = parts[m+DT1];
- dR = parts[d+DT1];
- yR = parts[y+DT1];
- parts[DT1] = mR;
- parts[DT2] = dR;
- parts[DT3] = yR;
-
- //----------------------------------------------------------------------------------
- // shift 'em around for the time only or stacked version
- //----------------------------------------------------------------------------------
-
- if(varCode & dtStack) {
- offset = ht + f.descent; // shift date rects up
- for(inx = DT1;inx<FONTINFO;inx++)
- OffsetRect(&parts[inx],0, - offset);
- }
- if(varCode & dtStack || varCode & timeOnly) { // shift time rects left
- offset = parts[HOURS].left - parts[DATE].left;
- for(inx = FRAMET;inx<DT1;inx++)
- OffsetRect(&parts[inx], - offset, 0);
- }
- if(varCode & dtStack && varCode & showAMPM) { // align arrows
- parts[UPTIME].left = parts[DOWNTIME].left = parts[DOWNDATE].left;
- parts[UPTIME].right = parts[DOWNTIME].right = parts[DOWNDATE].right;
- parts[FRAMET].left = parts[FRAMED].left;
- parts[FRAMET].right = parts[FRAMED].right;
- }
- }
-
- //==================================================================================
- // Convert seconds to a Pascal string containing the time
- //==================================================================================
- static void getTimeStr(ControlHandle theCtl, short varCode, long secs, Str31 string)
- {
- short i=0;
- long nl;
- Str31 s;
- DateTimeRec dtr;
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return;
-
- string[i++] = 5; // pascal string
-
- Secs2Date(secs,&dtr); // convert to DateTimeRec
-
- nl = dtr.hour; // convert the hours
- if(varCode & showAMPM) { // 12 hour display
- if(nl > 12)
- nl-=12;
- else // 24 hour display
- if(nl == 0 && ((**hCDEF).timeCycle == 0xFF))
- nl = 12;
- }
- NumToString(nl, s);
- if(nl > 9) {
- string[i++] = s[1];
- string[i++] = s[2];
- }
- else {
- string[i++] = '0';
- string[i++] = s[1];
- }
-
- string[i++] = (**hCDEF).timeSep;
-
- nl = dtr.minute; // convert the minutes
- NumToString(nl, s);
- if(nl > 9) {
- string[i++] = s[1];
- string[i++] = s[2];
- }
- else {
- string[i++] = '0';
- string[i++] = s[1];
- }
- if(varCode & showAMPM) { // fill in the AM/PM
- string[0] = 8; // and adjust string len
- string[i++] = ' ';
- if(dtr.hour > 11)
- string[i++] = 'P';
- else
- string[i++] = 'A';
- string[i++] = 'M';
- }
-
- }
-
- //==================================================================================
- // a "brain dead" little routine to return m, d, y order from Intl0 resource
- //==================================================================================
- static void getDateFmt(ControlHandle theCtl, short * m, short * d, short * y)
- {
- Intl0Hndl hInt;
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return;
-
- hInt = (Intl0Hndl)IUGetIntl(0);
-
- (**hCDEF).dateSep = (**hInt).dateSep;
- (**hCDEF).dateOrder = (**hInt).dateOrder;
- (**hCDEF).timeSep = (**hInt).timeSep;
- (**hCDEF).timeCycle = (**hInt).timeCycle;
-
- switch((**hCDEF).dateOrder){
- case 0:
- *m = 0;
- *d = 1;
- *y = 2;
- break;
- case 1:
- *m = 1;
- *d = 0;
- *y = 2;
- break;
- case 2:
- *m = 1;
- *d = 2;
- *y = 0;
- break;
- case 3:
- *m = 0;
- *d = 2;
- *y = 1;
- break;
- case 4:
- *m = 2;
- *d = 0;
- *y = 1;
- break;
- case 5:
- *m = 2;
- *d = 1;
- *y = 0;
- break;
- }
- }
- //==================================================================================
- // Convert seconds to a Pascal string containing the date, in
- // order specified in the Date & Time Control Panel
- //==================================================================================
- static void getDateStr(ControlHandle theCtl, long secs, Str31 string)
- {
- short i,m,d,y,dateTbl[3];
- long nl;
- Str31 s;
- DateTimeRec dtr;
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF)
- return;
-
- string[0] = 8; // 8 byte pascal string
- string[3] = string[6] = (**hCDEF).dateSep;
-
- Secs2Date(secs,&dtr); // convert to DateTimeRec
- getDateFmt(theCtl, &m, &d, &y); // get table indices
- dateTbl[m] = dtr.month; // and plug into local tbl
- dateTbl[d] = dtr.day;
- dateTbl[y] = dtr.year;
-
- i = m*3+1;
- nl = dateTbl[m]; // convert the month
- NumToString(nl, s);
-
- if(nl > 9) {
- string[i++] = s[1];
- string[i] = s[2];
- }
- else {
- string[i++] = '0';
- string[i] = s[1];
- }
-
- i = d*3+1;
- nl = dateTbl[d]; // convert the day
- NumToString(nl, s);
-
- if(nl > 9) {
- string[i++] = s[1];
- string[i] = s[2];
- }
- else {
- string[i++] = '0';
- string[i] = s[1];
- }
-
- i = y*3+1;
- nl = dateTbl[y] - (dateTbl[y]/100 * 100); // convert the year
- NumToString(nl, s);
-
- if(nl > 9) {
- string[i++] = s[1];
- string[i] = s[2];
- }
- else {
- string[i++] = '0';
- string[i] = s[1];
- }
- }
-
- //==================================================================================
- // A simple check to see if a partCode is one of the up/down arrows
- //==================================================================================
- static char arrowPart (short partCode)
- {
- if(partCode == UPTIME ||
- partCode == DOWNTIME ||
- partCode == UPDATE ||
- partCode == DOWNDATE)
- return true;
- return false;
- }
- //==================================================================================
- // create polygons for the arrow frame and both of the arrows
- //==================================================================================
-
- void makePolys(ControlHandle theCtl, short varCode)
- {
- short inx,c,v,w,b1,b2;
- Rect r,parts[NUMPARTS];
- dtcHandle hCDEF;
-
- hCDEF = (dtcHandle)(**theCtl).contrlData;
- if(!hCDEF) { // ooops!
- return;
- }
- getRects(theCtl, varCode, parts); // rects for control parts
- OffsetRect(&parts[FRAMET], // adjust to 0,0
- -parts[ALL].left, -parts[ALL].top);
- r = parts[FRAMET];
-
- for(inx=0;inx<2;inx++) {
- (**hCDEF).poly[3*inx] = OpenPoly(); // frame the arrows
-
- if((**hCDEF).poly[3*inx]) {
- MoveTo(r.left+2,r.top);
- LineTo(r.right-3, r.top);
- Line(2,3);
- LineTo(r.right-1, r.bottom-3);
- Line(-2,2);
- LineTo(r.left+2, r.bottom-1);
- Line(-2,-2);
- LineTo(r.left, r.top+3);
- Line(2,-3);
- ClosePoly();
- }
-
- c = (r.right - r.left)/2 + r.left;
- b1 = (r.right - r.left -2)/3;
- b2 = (r.right - r.left -2)/4;
- v = r.top+2;
- w = b2;
-
- (**hCDEF).poly[3*inx+1] = OpenPoly(); // draw UP arrow
-
- if((**hCDEF).poly[3*inx+1]) {
- MoveTo(c,v);
- Line(-b1,b1);
- Line(2,0);
- Line(0,b2);
- Line(w,0);
- Line(0,-b2);
- Line(2,0);
- Line(-b1,-b1);
- ClosePoly();
- }
-
- v = r.bottom-3;
- (**hCDEF).poly[3*inx+2] = OpenPoly(); // draw DOWN arrow
-
- if((**hCDEF).poly[3*inx+2]) {
- MoveTo(c,v);
- Line(-b1,-b1);
- Line(2,0);
- Line(0,-b2);
- Line(w,0);
- Line(0,b2);
- Line(2,0);
- Line(-b1,b1);
- ClosePoly();
- }
- OffsetRect(&parts[FRAMED], // adjust to 0,0
- -parts[ALL].left, -parts[ALL].top);
- r = parts[FRAMED];
- }
- }
-